#include "../../lib/algo/Sjf.h"


void Sjf::applySjf(vector<Travail> _travails){

	vector<Travail>	travails = _travails;  
	cout << "sjf: Travaux.size = " << travails.size() << endl;

	// "tri bull" pour avoir la liste incremantale des travaux, selon leurs durees(SJF): 
	int size = travails.size();
	Travail tmp;
	for (int a = 0; a < size - 1; a++){
		for (int b = 1; b < size; b++){
			if (travails[b].getDuree1() < travails[b-1].getDuree1()){
				tmp = travails[b];
				travails[b] = travails[b-1];
				travails[b-1] = tmp;
			}
		}
	}

	Exec mExec;

	mExec.insert(Exec::value_type("0", 0.00));		
	mExec.insert(Exec::value_type("1", 0.00));		
	mExec.insert(Exec::value_type("2", 0.00));		
	mExec.insert(Exec::value_type("3", 0.00));		
	mExec.insert(Exec::value_type("4", 0.00));		
	mExec.insert(Exec::value_type("5", 0.00));		
	mExec.insert(Exec::value_type("6", 0.00));		
	mExec.insert(Exec::value_type("7", 0.00));		
	mExec.insert(Exec::value_type("8", 0.00));		

// Debogage °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
	cout << "sjf : mExec.size = " << mExec.size() << endl;
	for (int i = 0; i < travails.size(); i++){
//		cout<< "element ID - " << travails[i].getIdTravail();
		cout<< "element Duree - " << travails[i].getDuree1();
		cout<< "\t Machines - " << travails[i].getNbrMachine() <<endl;	
	}
// Debogage °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
	float minBis = 0;
	float tempsMin;
	float count;
	FFMMap nbrMLibre;
	vector<string> listeMachineLibres;

	for (int i = 0; i < travails.size(); i++) {

		tempsMin = findMin(mExec, minBis);
		count = compter(mExec, tempsMin);

		nbrMLibre.insert(make_pair(count,tempsMin));
		
		FFMMap::iterator pos1;
		float nbrM = 0; //nbr des machines disponible
		for (pos1 = nbrMLibre.begin(); pos1 != nbrMLibre.end(); ++pos1) {
			nbrM += (float)pos1->first;
//		        cout <<"res du MMap : "  << pos1->second << endl;
    		}

		// ============== Appeler faireExecuter() =================
		if (travails[i].getNbrMachine() <= nbrM){
//			cout << "tx machines = " << travails[i].getNbrMachine() << "\t nbrM dispo = " << nbrM <<endl;
//			cout << "nbrM is OK" << endl;
			listeMachineLibres = Sjf::listeMachineLibre(nbrMLibre, mExec, nbrM);
//			cout << "listMachineLibres : " << listeMachineLibres.size() <<endl;
			mExec = Sjf::faireExecuter(mExec, listeMachineLibres, travails[i]);
			listeMachineLibres.clear();
			nbrMLibre.clear();
		}
		else {
			while (nbrM < travails[i].getNbrMachine()){
	
/*			float min = Graham::findMin(mExec, minBis);
			cout << "min = " << min << endl;*/
			
				Sjf::findMinBis(mExec, minBis, tempsMin);
//			cout << "minBis = " << minBis << endl;
		
				tempsMin = minBis;
				count = compter(mExec, tempsMin);
//			cout << "count = " << count << endl;

 				nbrMLibre.insert(make_pair(count,tempsMin));
				for (pos1 = nbrMLibre.begin(); pos1 != nbrMLibre.end(); ++pos1) {
//				        cout <<"nbr Machine dans nbeMLibre : "  << pos1->first << endl;
		    		}
				nbrM += count;
//			cout << "nbrM WHILE = " << nbrM << endl;
	
			}//fin WHILE

			listeMachineLibres = Sjf::listeMachineLibre(nbrMLibre, mExec, nbrM);
			mExec = Sjf::faireExecuter(mExec, listeMachineLibres, travails[i]);

			listeMachineLibres.clear();
			nbrMLibre.clear();

		
		}// fin ELSE

//		cout << "sjf: count = " << count << endl;

	}//fin FOR TX
}
// ============= Fonction de findMin() ====================
//  cette fonction trouve le temps minimum c.a.d. 	===
//  les machines qui finisse les travaux le plus tot 	===
// ========================================================

float Sjf::findMin(Exec mExec, float & minBis){
	Exec::iterator pos;
	float min = 999999;

	for(pos = mExec.begin(); pos != mExec.end(); ++pos) {
		if (pos->second <= min){
			min = pos->second;
		}
    	}//fin FOR
//	minBis = min;
	return min;
}

// ============= Fonction de findMinBis() ====================
//  cette fonction trouve le temps de fin du ravail de la ====
//  machine suivante, dont le tmps plus proche de min ========
// ===========================================================

float Sjf::findMinBis(Exec mExec, float & minBis, float _min){
	Exec::iterator pos;
	float min = _min;
	minBis = 9999999;

	for(pos = mExec.begin(); pos != mExec.end(); ++pos) {
		if (pos->second > min & minBis >= pos->second){
//			min = pos->second;
			minBis = pos->second;
		}
    	}//fin FOR
//	cout << "dans minBis : minBis = " << minBis << endl;
	return min;
}

// ============= Fonction de compter() ====================
//  cette fonction compte le nombre de machines ===========
//  avec le meme temps 	===================================
// ======================================================
float Sjf::compter(Exec mExec, float _tempsMin){
	Exec::iterator pos;
	float min = _tempsMin;
	float count = 0;

	for(pos = mExec.begin(); pos != mExec.end(); ++pos) {
		if (pos->second == min){
			count++;
		}
    	}//fin FOR
	return count;
}

// ============= Fonction listeMachineLibre()==============
//  cette fonction return les IP de machines	===========
//  qui finissent leurs travail à temps Min	===========
//  calcule par la fonction findMin()		===========
// ========================================================

vector<string> Sjf::listeMachineLibre(FFMMap nbrMLibres, Exec mExec, float nbrMachine){

	FFMMap::iterator pos1;
	FFMMap::reverse_iterator rpos; 
	Exec::iterator pos2;
	vector<string> listeMachineLibre;
	string ipMachine;

/*			for (pos1 = nbrMLibres.begin(); pos1 != nbrMLibres.end(); ++pos1) {
			        cout <<"nbr Machine dans nbeMLibres --- : "  << pos1->first << endl;
	    		}
*/
	for(rpos = nbrMLibres.rbegin(); rpos != nbrMLibres.rend(); ++rpos) {
		float t = rpos->second;
//		cout << "Graham::listeMachineLibre : time = " << t << endl;
		for (pos2 = mExec.begin(); pos2 != mExec.end(); ++pos2) {
			if (pos2->second == t){
				ipMachine = pos2->first;
				listeMachineLibre.push_back(ipMachine);
			}//fin IF
		}//fin FOR II listeMachineLibre
    	}//fin FOR I
//	cout << "Graham::listeMachineLibre : liste size = " << listeMachineLibre.size() << endl;
/*	for (int i = 0; i < listeMachineLibre.size(); i++) {	
		cout << "Graham::listeMachineLibre : ip " << listeMachineLibre[i] << endl;
	}*/
	return listeMachineLibre;
}

// ============= Fonction faireExecuter() =================
//  cette fonction execute les travaux ====================
// ========================================================

map<string, float> Sjf::faireExecuter(Exec mExec, vector<string> lML, Travail travail){

	Exec::iterator pos, pos2;
	int duree = travail.getDuree1();
	int nbrMachine = travail.getNbrMachine();
//	cout<<"nbrMachine besoin = "<< nbrMachine <<endl;
	string ip;
	string str;
	float time, max;
	str = lML[0];

//	cout << "faireExec : size du lML : " << lML.size() << endl;
//	for (int i = 0; i < lML.size(); i++){
//		cout << "lML ip : " << lML[i] << endl;
//	}
//	cout << "premier temps de lML dans FExec : " << str << endl;
	//besoin du temps sur lequel on va ajuster les autres
	for(pos = mExec.begin(); pos != mExec.end(); ++pos) {
		if (pos->first == str){
			max = pos->second;
		}
	}//fin FOR 

//	cout << "premier temps de lML dans FExec MAX: " << max << endl;
	for(int i = 0; i < nbrMachine; i++){
//		mExec.insert(Exec::value_type(lML[i], duree));		

		str = lML[i]; //recuperer ip de la machine libre
		ip = mExec.find(str)->first; //recuperer ip de machine a la qulle on va affecter le travail
		//recuperer le temps(quand il fini le travail precedant) de machine a qulle on va affecter le travail
		time = mExec.find(str)->second; 
		mExec.erase(str); //effacer l'element trouver, pour inserer nouvelle element 
		
		// la partie ou on ajouste le temps quand cette machine fini son dernier travail
		time = time + (max - time);

		time += duree; //augmanter le temps
		
//		cout<<"dans faireExecuter ip ajuster = " << ip <<endl;
//		cout<<"dans faireExecuter time ajuster = " << time <<endl;

		mExec.insert(Exec::value_type(ip, time)); //inserer l'element change

	}//fin FOR
	// Debogage °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
		for (pos2 = mExec.begin(); pos2 != mExec.end(); ++pos2) {
			cout << "ip : " << pos2->first << "\t time : " << pos2->second << endl;
		}//fin FOR
		cout << endl;
	// Debogage °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
	return mExec;
}



 
